package com.mrd.gtimp.base.Identifier;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Property;
import org.hibernate.internal.CriteriaImpl;
import org.hibernate.internal.CriteriaImpl.Subcriteria;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;


/**
 * <p> application name: sample <p> copyright: Copyright@2012 明睿达科技有限公司
 */

/**
 * 该类为排序类
 *
 * @author qiul
 */
public class Order {
    /**
     * Logger for this class
     */
    private static final Logger logger = Logger.getLogger(Order.class);

    private Map<String, Boolean> orders;
    /**
     * 正序标志
     */
    public static final String ASC = "asc";
    /**
     * 倒序标志
     */
    public static final String DESC = "desc";

    public Order() {
        orders = new HashMap<String, Boolean>();
    }

    public Order(String column) {
        orders = new HashMap<String, Boolean>();
        orders.put(column, false);
    }

    public int size() {
        return orders.size();
    }

    public boolean isEmpty() {
        return orders.isEmpty();
    }

    public boolean containsKey(Object key) {
        return orders.containsKey(key);
    }

    public boolean containsValue(Object value) {
        return orders.containsValue(value);
    }

    public Boolean get(Object key) {
        return orders.get(key);
    }

    /**
     * 添加排序属性
     *
     * @param columnName 字段名
     * @param isDesc     是否为倒序，true为倒序,false为正序
     */
    public Boolean add(String columnName, Boolean isDesc) {
        if (StringUtils.isEmpty(columnName)) {
            return false;
        }
        return orders.put(columnName, isDesc);
    }

    /**
     * 添加排序属性
     *
     * @param columnName 字段名
     * @param desc       排序顺序,desc为倒序，asc为正序
     * @return 排序字段添加是否成功
     */
    public Boolean add(String columnName, String desc) {
        if (DESC.equals(desc)) {
            return add(columnName, true);
        } else if (ASC.equals(desc)) {
            return add(columnName);
        } else {
            logger.info("添加排序字段失败，因为排序顺序不为正序也不为逆序!");
            return false;
        }
    }

    /**
     * 按正序添加排序属性
     *
     * @param columnName 字段名
     */
    public Boolean add(String columnName) {
        return add(columnName, false);
    }

    public Boolean remove(Object key) {
        return orders.remove(key);
    }

    public void clear() {
        orders.clear();
    }

    public Set<String> keySet() {
        return orders.keySet();
    }

    public Collection<Boolean> values() {
        return orders.values();
    }

    public Set<Entry<String, Boolean>> entrySet() {
        return orders.entrySet();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((orders == null) ? 0 : orders.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        Order other = (Order) obj;
        if (orders == null) {
            if (other.orders != null) {
                return false;
            }
        } else if (!orders.equals(other.orders)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "Order [orders=" + orders + "]";
    }

    /**
     * 为Criteria添加排序
     */
    public Criteria setOrder(Criteria criteria) {
        if (criteria == null) {
            return null;
        }
        for (String columnName : orders.keySet()) {
            if (orders.get(columnName)) {
                criteria.addOrder(Property.forName(columnName).desc());
            } else {
                criteria.addOrder(Property.forName(columnName).asc());
            }
        }
        return criteria;
    }

    /**
     * 为DetachedCriteria添加排序
     */
    @SuppressWarnings("rawtypes")
    public DetachedCriteria setOrder(DetachedCriteria dc) {
        String entityName = dc.getAlias();
        List<String> tables = null;
        for (String column : orders.keySet()) {
            String tableName = "";
            String field = column;
            if (field.indexOf(".") != -1) {
                String[] tmp = field.split("\\.");
                for (int i = 0; i < tmp.length - 1; i++) {
                    tableName = tmp[i];
                    if (tables == null) {
                        tables = new ArrayList<String>();
                        tables.add(tableName);
                    } else {
                        if (!tables.contains(tableName)) {
                            tables.add(tableName);
                        }
                    }
                    try {
                        CriteriaImpl impl = (CriteriaImpl) dc.getClass().getDeclaredField("impl")
                                .get(dc);
                        Iterator iterator = impl.iterateSubcriteria();
                        while (iterator.hasNext()) {
                            Subcriteria s = (Subcriteria) iterator.next();
                            if (!s.getAlias().equals(tableName)) {
                                if (i == 0) {
                                    dc.createAlias(tableName, tableName);
                                } else {
                                    dc.createAlias(tmp[i - 1] + "." + tableName, tableName);
                                }
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                field = tableName + "." + tmp[tmp.length - 1];
            } else {
                field = entityName + "." + field;
            }
            if (orders.get(column)) {
                dc.addOrder(org.hibernate.criterion.Order.desc(field));
            } else {
                dc.addOrder(org.hibernate.criterion.Order.asc(field));
            }
        }
        return dc;
    }
}
